home *** CD-ROM | disk | FTP | other *** search
- /*
- ** <<< Morse Code Functions >>>
- **
- ** Written by Michael M. Dodd, N4CF, and placed in the public domain.
- **
- ** The morse() function transmits a string in Morse code on the IBM PC's
- ** speaker. The speed is set by a program constant (UNIT_TIME).
- **
- ** There are several other functions in this file, all used by morse(),
- ** and defined ahead of morse() for convenience.
- **
- ** The main() function at the end of the file is a test program to send
- ** the command-line argument string in morse code. Enclose multiple
- ** words in quotes. Example: morse "hello, world"
- **
- ** These functions have been compiled and tested in the Small and Large
- ** memory models using Microsoft C 6.00a.
- **
- ** Modified for ZTC++, TC++, & BC++ by Bob Stout
- */
-
- #include <stdio.h>
- #include <dos.h>
- #include <conio.h>
- #include <ctype.h>
-
- /*
- ** These functions turn on and off the CW tone on the PC's speaker. The
- ** frequency is specified by the freq argument.
- ** IMPORTANT! These functions are highly IBM PC-specific!
- */
-
- #define CLK_FREQ (1193180L)
- #define PIO (0x61)
- #define CTC_CMD (0x43)
- #define CTC_DATA (0x42)
- #define SETUP (0xB6)
- #define TONE_ON (0x03)
- #define TONE_OFF (0xFC)
-
- void note_on (int freq) /* Turn on the tone. */
- {
- int divisor ;
- int pio_word ;
-
- divisor = (int)(CLK_FREQ / (long)(freq)) ;
- outp (CTC_CMD, SETUP) ;
- outp (CTC_DATA, divisor & 0xFF) ;
- outp (CTC_DATA, divisor >> 8) ;
- pio_word = inp (PIO) ;
- outp (PIO, pio_word | TONE_ON) ;
- }
-
- void note_off (void) /* Turn off the tone. */
- {
- int pio_word ;
-
- pio_word = inp (PIO) ;
- outp (PIO, pio_word & TONE_OFF) ;
- }
-
- /*
- ** These functions implement a timing-loop delay. Because the PC's
- ** internal clock is too coarse for accurate CW timing, the pause()
- ** function uses a simple software loop to produce a delay.
- **
- ** To minimize the effects of CPU clock speed, the calib() function
- ** returns a number which represents a rough index of the clock speed
- ** with relation to the standard IBM PC (this is very approximate).
- **
- ** Calibration is performed only once, when the static fudge_factor is
- ** zero. Thereafter, the contents of fudge_factor are used to form a
- ** delay value.
- **
- ** IMPORTANT! These functions are highly IBM PC-specific!
- */
-
- unsigned int calib (void)
- {
- unsigned int far *timerLow = (unsigned int far *)(0x046c) ;
- unsigned int lastTime ;
- unsigned int iter ;
-
- for (lastTime = *timerLow; lastTime == *timerLow;)
- ;
-
- for (iter = 0, lastTime = *timerLow; lastTime == *timerLow; iter++)
- ;
- #if defined(__ZTC__)
- return ((unsigned int)((125L * ((long)(iter)) + 50L) / 2300L)) ;
- #elif defined(__TURBOC__)
- return ((unsigned int)((77L * ((long)(iter)) + 50L) / 2300L)) ;
- #else /* assume MSC */
- return ((unsigned int)((100L * ((long)(iter)) + 50L) / 2300L)) ;
- #endif
- }
-
- void pause (unsigned int amount)
- {
- static unsigned int fudge_factor = 0 ;
- unsigned long ul ;
-
- if (fudge_factor == 0) /* Calibrate the speed. */
- fudge_factor = calib () ;
-
- ul = (unsigned long)(amount) * (long)(fudge_factor) ;
- while (ul--) /* Delay. */
- ;
- }
-
- /*
- ** These functions transmit a dot, a dash, a letter space, and a
- ** word space.
- **
- ** Note that a single unit space is automatically transmitted after
- ** each dot or dash, so the ltr_space() function produces only a
- ** two-unit pause.
- **
- ** Also, the word_space() function produces only a four-unit pause
- ** because the three-unit letter space has already occurred following
- ** the previous letter.
- */
-
- #define SPACE_MASK (1 << 15)
- #define BIT_MASK (0xfe)
- #define UNIT_TIME (18)
- #define FREQUENCY (1500)
-
- void send_dot (void) /* Send a dot and a space. */
- {
- note_on (FREQUENCY) ;
- pause (UNIT_TIME) ;
- note_off () ;
- pause (UNIT_TIME) ;
- }
-
- void send_dash (void) /* Send a dash and a space. */
- {
- note_on (FREQUENCY) ;
- pause (UNIT_TIME * 3) ;
- note_off () ;
- pause (UNIT_TIME) ;
- }
-
- void ltr_space (void) /* Produce a letter space. */
- {
- pause (UNIT_TIME * 2) ;
- }
-
- void word_space (void) /* Produce a word space. */
- {
- pause (UNIT_TIME * 4) ;
- }
-
-
- /*
- ** MORSE () - Transmit a string in Morse code
- **
- ** This function transmits the string pointed to by the cp argument in
- ** Morse code on the PC's speaker. The speed is set by the UNIT_TIME
- ** constant.
- **
- ** A static table translates from ASCII to Morse code. Each entry is
- ** an unsigned integer, where a zero represents a dot and a one
- ** represents a dash. No more than 14 bits may be used. Setting bit
- ** 15 produces a word space, regardless of any other pattern.
- **
- ** The Morse code pattern is taken from bit 0, and is shifted right
- ** each time an element is sent. A special "marker bit" follows the
- ** complete Morse pattern. This marker bit is tested before
- ** transmitting each bit; if there are no 1's in bits 1..15, the
- ** complete character has been sent.
- **
- ** For example, an "L" would be 0000000000010010, with bit zero
- ** containing the first dot, bit one the dash, etc. The marker
- ** bit is in bit 4.
- */
-
- void morse (char *cp)
- { /*--- MORSE CODE FUNCTION ---*/
-
- unsigned int c ;
- static unsigned int codes [64] = {
- SPACE_MASK, /* Entry 0 = space (0x20) */
- 0, 0, 0, 0, 0, 0, 0, 0, /* ! " # $ % & " ( */
- 0, 0, 0, 115, 49, 106, 41, /* ) * + , - . / */
- 63, 62, 60, 56, 48, 32, 33, 35, /* 0 1 2 3 4 5 6 7 */
- 39, 47, 0, 0, 0, 0, 0, 76, /* 8 9 : ; < = > ? */
- 0, 6, 17, 21, 9, 2, 20, 11, /* @ A B C D E F G */
- 16, 4, 30, 13, 18, 7, 5, 15, /* H I J K L M N O */
- 22, 27, 10, 8, 3, 12, 24, 14, /* P Q R S T U V W */
- 25, 29, 19 /* X Y Z */
- } ;
-
- pause (0) ; /* Calibrate pause() function. */
-
- while ((c = *cp++) != '\0')
- { /*--- TRANSMIT COMPLETE STRING ---*/
-
- c = toupper (c) ; /* No lower-case Morse characters. */
- c -= ' ' ; /* Adjust for zero-based table. */
-
- if (c < 0 || c > 58) /* If out of range, ignore it. */
- continue ;
-
- c = codes[c] ; /* Look up Morse pattern from table. */
-
- if (c & SPACE_MASK) /* If the space bit is set.. */
- { /* ..send a word space and go on. */
- word_space () ;
- continue ;
- }
-
- while (c & BIT_MASK) /* Transmit one character. */
- { /*--- TRANSMIT EACH BIT ---*/
- if (c & 1)
- send_dash () ;
- else send_dot () ;
-
- c >>= 1 ;
- } /*--- TRANSMIT EACH BIT ---*/
-
- ltr_space () ; /* Send a space following character. */
-
- } /*--- TRANSMIT COMPLETE STRING ---*/
-
- } /*--- MORSE CODE FUNCTION ---*/
-
-
- /*
- ** This is the test program, which transmits argv[1] in Morse code.
- */
-
- void main (int argc, char *argv[])
- {
- if (argc > 1)
- morse (argv[1]) ;
- }
-